/**
 * 
 */
package ar.org.tesis.comparticion.conocimientos.jms.remoting;

import java.util.List;

import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageFormatException;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TextMessage;

import org.apache.commons.lang.StringUtils;
import org.springframework.jms.support.JmsUtils;
import org.springframework.jms.support.converter.MessageConverter;
import org.springframework.jms.support.converter.SimpleMessageConverter;
import org.springframework.remoting.support.RemoteInvocation;
import org.springframework.remoting.support.RemoteInvocationResult;

import ar.org.tesis.comparticion.conocimientos.informacion.Mensaje;
import ar.org.tesis.comparticion.conocimientos.informacion.beans.TeoriaBean;
import ar.org.tesis.comparticion.conocimientos.utils.XstreamUtils;

/**
 * @author Marcelo
 *
 */
public class JmsInvokerServiceExporter extends
		org.springframework.jms.remoting.JmsInvokerServiceExporter {
	
	private MessageConverter messageConverter;
	private boolean ignoreInvalidRequests;
	private Object proxy;

	public JmsInvokerServiceExporter() {
		messageConverter = new SimpleMessageConverter();
		ignoreInvalidRequests = true;
	}

	public void setMessageConverter(MessageConverter messageConverter) {
		this.messageConverter = ((MessageConverter) (messageConverter == null ? ((MessageConverter) (new SimpleMessageConverter()))
				: messageConverter));
	}

	public void setIgnoreInvalidRequests(boolean ignoreInvalidRequests) {
		this.ignoreInvalidRequests = ignoreInvalidRequests;
	}

	public void afterPropertiesSet() {
		proxy = getProxyForService();
	}

	public void onMessage(Message requestMessage, Session session)
			throws JMSException {
		Mensaje mensaje=readRemoteInvocationTextMessage(requestMessage);
		Object arguments[]=null;
		Class<?> parameterTypes[]=null;
		if(mensaje.getTeorias()==null && StringUtils.isNotEmpty(mensaje.getSiaName())&&StringUtils.isNotEmpty(mensaje.getWorldName())){
			arguments=new Object[]{mensaje.getSiaName(),mensaje.getWorldName()};
			parameterTypes=new Class<?>[]{String.class,String.class};
		}else
			if(mensaje.getTeoria()!=null){
				arguments=new Object[]{mensaje.getTeoria()};
				parameterTypes=new Class<?>[]{TeoriaBean.class};
			}else{
				if(StringUtils.isNotEmpty(mensaje.getIdTeoria())){
					arguments=new Object[]{mensaje.getIdTeoria()};
					parameterTypes=new Class<?>[]{String.class};
				}else{
					arguments=new Object[]{mensaje.getSiaName(),mensaje.getWorldName(),mensaje.getTeorias()};
					parameterTypes=new Class<?>[]{String.class,String.class,List.class};
				}
			}
		RemoteInvocation invocation = new RemoteInvocation(mensaje.getNombreMetodo(),parameterTypes,arguments);
		if (invocation != null) {
			RemoteInvocationResult result = invokeAndCreateResult(invocation,proxy);
			
			writeRemoteInvocationResult(requestMessage, session, result);
		}
	}

	protected Mensaje readRemoteInvocationTextMessage(Message requestMessage)
			throws JMSException {
		Object content = messageConverter.fromMessage(requestMessage);
		if (content instanceof String){
			final Mensaje mensaje=XstreamUtils.getMensaje(content.toString());
			return mensaje;
		}
		onInvalidRequestMessage(requestMessage);
		return null;
	}
	
	protected void writeRemoteInvocationResult(Message requestMessage, Session session, RemoteInvocationResult result)
    throws JMSException
	{
	    Message response;
	    MessageProducer producer=null;
	    try{
		    response = createResponseMessage(requestMessage, session, result);
		    producer = session.createProducer(requestMessage.getJMSReplyTo());
		    TextMessage reply =session.createTextMessage();
		    reply.setText((String)result.getValue());
            reply.setJMSCorrelationID(response.getJMSMessageID());
		    producer.send(reply);
		    JmsUtils.closeMessageProducer(producer);
	    }catch (Exception e) {
			// TODO: handle exception
	    	logger.error(e);
		}finally{
	    	JmsUtils.closeMessageProducer(producer);
		}
	   
	    return;
	}


	protected Message createResponseMessage(Message request, Session session,
			RemoteInvocationResult result) throws JMSException {
		Message response = messageConverter.toMessage(result, session);
		String correlation = request.getJMSCorrelationID();
		if (correlation == null)
			correlation = request.getJMSMessageID();
		response.setJMSCorrelationID(correlation);
		return response;
	}

	protected void onInvalidRequestMessage(Message requestMessage)
			throws JMSException {
		if (ignoreInvalidRequests) {
			if (logger.isWarnEnabled())
				logger.warn((new StringBuilder(
						"Invalid request message will be discarded: ")).append(
						requestMessage).toString());
		} else {
			throw new MessageFormatException((new StringBuilder(
					"Invalid request message: ")).append(requestMessage)
					.toString());
		}
	}
}
